using System;
using System.Data;
using System.Collections.Generic;
using System.Reflection;
using System.Globalization;
using System.Text;

using Kenly.DBFramework.Gateway;

namespace Kenly.DBFramework.Reflection
{
    /// <summary>
    /// Mapping tool between entity and database.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class EntityMapper<T> where T : new()
    {
        /// <summary>
        /// To keep the column names the same as the property names .
        /// </summary>
        /// <param name="rawTable">the table with the same schema of database.</param>
        public static void AdaptToEntity(DataTable rawTable)
        {
            EntityMapper.AdaptToEntity(rawTable, typeof(T));
        }


        /// <summary>
        /// To keep the column names the same as the schema of database.
        /// </summary>
        /// <param name="adaptedTable"></param>
        public static void AdaptToDatabase(DataTable adaptedTable)
        {
            EntityMapper.AdaptToDatabase(adaptedTable, typeof(T));
        }


        /// <summary>
        /// Creates a array of entities each of whose property's value is retrieved from rows in a table. The property must contain a ColumnAttribute.
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        public static List<T> ToEntities(DataTable table)
        {
            if (table == null)
            {
                return new List<T>();
            }

            return ToEntities(table.Rows);
        }

        /// <summary>
        /// Creates a array of entities each of whose property's value is retrieved from rows in a table. The property must contain a ColumnAttribute.
        /// </summary>
        /// <param name="adaptedRows"></param>
        /// <returns></returns>
        public static List<T> ToEntities(DataRowCollection adaptedRows)
        {
            if (adaptedRows == null || adaptedRows.Count <= 0)
            {
                return new List<T>();
            }

            List<T> entities = ObjectBuilder.CreateInstances<T>(adaptedRows.Count);
            CopyToEntities(entities, adaptedRows);

            return entities;
        }


        /// <summary>
        /// Creates a entity each of whose property's value is retrieved from a row. The property must contain a ColumnAttribute.
        /// </summary>
        /// <param name="adaptedRow"></param>
        /// <returns></returns>
        public static T ToEntity(DataRow adaptedRow)
        {
            T entity = ObjectBuilder.CreateInstance<T>();
            if (adaptedRow == null)
            {
                return entity;
            }

            CopyToEntity(entity, adaptedRow);

            return entity;
        }




        /// <summary>
        ///  Copies values to a array of entities from rows in a table. The property must contain a ColumnAttribute.
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="adaptedTable"></param>
        public static void CopyToEntities(IList<T> entities, DataTable adaptedTable)
        {
            EntityMapper.CopyToEntities(entities, adaptedTable);
        }

        /// <summary>
        ///  Copies values to a array of entities from rows in a table. The property must contain a ColumnAttribute.
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="adaptedRows"></param>
        public static void CopyToEntities(IList<T> entities, DataRowCollection adaptedRows)
        {
            EntityMapper.CopyToEntities(entities, adaptedRows);
        }


        /// <summary>
        /// Copies values to a entity from a row.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="adaptedRow"></param>
        public static void CopyToEntity(T entity, DataRow adaptedRow)
        {
            EntityMapper.CopyToEntity(entity, adaptedRow);
        }

        /// <summary>
        /// Indicates if it is possible to copy values to a entity from a row.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="adaptedRow"></param>
        /// <returns></returns>
        public static bool CanCopyToEntity(T entity, DataRow adaptedRow)
        {
            return EntityMapper.CanCopyToEntity(entity, adaptedRow);
        }

        /// <summary>
        /// Creates a table each of whose rows is reflected from the entity properties.The state of all rows is Added state.
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public static DataTable ToTable(IList<T> entities)
        {
            return ToTable(entities, true);
        }


        /// <summary>
        /// Creates a table each of whose rows is reflected from the entity properties or database columns.The state of all rows is Added state.
        /// </summary>
        /// <param name="isAdapted"></param>
        /// <param name="entities"></param>
        /// <returns></returns>
        public static DataTable ToTable(IList<T> entities, bool isAdapted)
        {
            if (entities == null || entities.Count <= 0 ||
                typeof(T).GetProperties().Length <= 0)
            {
                DataTable newTable = new DataTable(typeof(T).Name);
                newTable.Locale = System.Globalization.CultureInfo.InvariantCulture;
                return newTable;
            }

            return EntityMapper.ToTable(entities, isAdapted);
        }

        /// <summary>
        ///  Creates a DataTable with the same schema of the entity.
        /// </summary>
        /// <returns></returns>
        public static DataTable CreateTable()
        {
            return CreateTable(true);
        }

        /// <summary>
        /// Creates a DataTable with the same schema of the entity.
        /// </summary>
        /// <param name="isAdapted"></param>
        /// <returns></returns>
        public static DataTable CreateTable(bool isAdapted)
        {
            return EntityMapper.CreateTable(typeof(T), isAdapted);
        }


        /// <summary>
        /// Maps property name to column name.
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static string ToColumnName(string propertyName)
        {
            return EntityMapper.ToColumnName(propertyName, typeof(T));
        }

        /// <summary>
        ///  Maps column name to property name.
        /// </summary>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public static string ToPropertyName(string columnName)
        {
            return EntityMapper.ToPropertyName(columnName, typeof(T));
        }


        /// <summary>
        /// Creates a list of instances.
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public static List<T> CreateEntities(int count)
        {
            if (count <= 0)
            {
                return new List<T>();
            }
            return ObjectBuilder.CreateInstances<T>(count);
        }

    }
}